package com.openess.bigsearch.engine.Text;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;

import com.openess.bigsearch.engine.BTree.util.ByteArrays;

/**
 * 保存Raw序列，代表一个文档id的所有域文本
 * 
 * @author TuTu
 * 
 */
public class TextRaw {
	/**
	 * 保存域的原文本
	 * 
	 * @author TuTu
	 * 
	 */
	public class Raw {
		private String fieldname;
		private String raw;

		private int headsize = 2;
		/**
		 * 头数据，字符长度
		 */
		private byte[] head;
		/**
		 * field:raw的字节长度
		 */
		private int length;

		public Raw() {
			head = new byte[headsize];
		}

		public Raw(String fieldname, String raw) {
			this();
			this.raw = raw;
			this.fieldname = fieldname;
			// 1是field和raw的分隔符":"的大小
			length = fieldname.length() + raw.length() + 1;
		}

		public String getFieldname() {
			return fieldname;
		}

		public String getRaw() {
			return raw;
		}

		/**
		 * 一次读取一个域文本
		 * 
		 * @param cf
		 * @param offset
		 * @return
		 * @throws IOException
		 */
		private long read(FileChannel cf, long offset) throws IOException {
			length = readHead(cf, offset);
			offset += headsize;
			byte[] strbyte = new byte[length * 2];
			ByteBuffer buf = ByteBuffer.wrap(strbyte);
			cf.read(buf, offset);
			String str = ByteArrays.getString(strbyte, 0, length);
			int index = str.indexOf(":");
			if (index < 0) {
				int n = 0;
			}
			fieldname = str.substring(0, index);
			raw = str.substring(index + 1);
			return offset + length * 2;
		}

		/**
		 * 读取头数据，field:raw的总长度，包括分隔符":"
		 * 
		 * @param cf
		 * @param offset
		 * @return
		 * @throws IOException
		 */
		private int readHead(FileChannel cf, long offset) throws IOException {
			ByteBuffer buf = ByteBuffer.wrap(head);
			cf.read(buf, offset);
			int length = ByteArrays.getShort(head, 0);
			return length;
		}

		/**
		 * 将原文本写入磁盘
		 * 
		 * @param cf
		 * @param index
		 *            raw的存储偏移量
		 * @throws IOException
		 */
		public long write(FileChannel cf, long offset) throws IOException {
			String str = fieldname + ":" + raw;
			// putString自动包含了头数据
			byte[] strbyte = ByteArrays.putString(str);
			ByteBuffer buf = ByteBuffer.wrap(strbyte);
			cf.write(buf, offset);
			return offset + headsize + length * 2;
		}
	}

	// 头数据的大小
	public int headsize = 1;
	// 保存了域文本的域数量
	public byte[] head;

	/**
	 * 代表一个文档id的所有域文本
	 */
	private ArrayList<Raw> rlist;

	public TextRaw() {
		head = new byte[headsize];
		rlist = new ArrayList<Raw>();
	}

	public void add(String fieldname, String raw) {
		rlist.add(new Raw(fieldname, raw));
	}

	public ArrayList<Raw> getRlist() {
		return rlist;
	}

	/**
	 * 读取一个文档id的所有数据
	 * 
	 * @param cf
	 * @param offset
	 * @return
	 * @throws IOException
	 */
	public void read(FileChannel cf, long offset) throws IOException {
		int size = readHead(cf, offset);
		offset += headsize;
		Raw r = null;
		for (int i = 0; i < size; i++) {
			r = new Raw();
			offset = r.read(cf, offset);
			rlist.add(r);
		}
	}

	/**
	 * 读取头数据，rlist的长度
	 * 
	 * @param cf
	 * @param offset
	 * @throws IOException
	 */
	private int readHead(FileChannel cf, long offset) throws IOException {
		ByteBuffer buf = ByteBuffer.wrap(head);
		cf.read(buf, offset);
		int size = ByteArrays.getByte(head, 0);
		return size;
	}

	/**
	 * 将一个文档id的所有域文本全部写入磁盘
	 * 
	 * @param rf
	 * @param offset
	 *            多个Raw中的起始偏移量
	 * @throws IOException
	 */
	public long write(FileChannel cf, long offset) throws IOException {
		if (offset == 15924) {
			int n = 0;
		}
		offset = writeHead(cf, offset);
		for (Raw raw : rlist)
			offset = raw.write(cf, offset);
		return offset;
	}

	/**
	 * 写入头数据，rlist的长度
	 * 
	 * @param cf
	 * @param offset
	 * @return
	 * @throws IOException
	 */
	private long writeHead(FileChannel cf, long offset) throws IOException {
		ByteArrays.putByte((byte) rlist.size(), head, 0);
		ByteBuffer buf = ByteBuffer.wrap(head);
		cf.write(buf, offset);
		return offset + headsize;
	}
}
